# 用于启动和监控上传数据的子进程，仅需要python标准安装包
import tkinter as tk
from tkinter import ttk, Menu,scrolledtext,filedialog, messagebox as msg
from subprocess import Popen
import sys
import os
import logging
import asyncio

logger = logging.getLogger('GUI')

class ProcessTab():
    """
    start and monitor subprocess
    """
    def __init__(self, master):
        self.master = master
        self.subp=None
        self._create_widgets()

    def _create_widgets(self):
        # frame
        self.frame = ttk.LabelFrame(self.master, text='进程控制')
        self.frame.grid(column=0, row=0,sticky='WE')

        # 按钮
        self.run_btn = ttk.Button(self.frame, text='run', command=self._run)
        self.run_btn.grid(column=0, row=0)

        self.stop_btn = ttk.Button(self.frame, text='stop', state='disabled',command=self._stop)
        self.stop_btn.grid(column=2, row=0)

        #self.close_tab_btn = ttk.Button(
        #    self.frame, text='close tab', command=self._close)
        #self.close_tab_btn.grid(column=2, row=0)

        # 可执行文件
        self.exec_fn_label = ttk.Label(self.frame, text='可执行python文件:')
        self.exec_fn_label.grid(column=0, row=1)
        self.exec_fn = tk.StringVar()
        self.exec_fn.set('test_log.py')
        self.exec_fn_entry = ttk.Entry(self.frame, textvariable=self.exec_fn)
        self.exec_fn_entry.grid(column=1, row=1)
        self.exec_fn_btn = ttk.Button(
            self.frame, text='...', command=self._get_exec_fn)
        self.exec_fn_btn.grid(column=2, row=1)

        # 日志文件
        self.log_fn_label = ttk.Label(self.frame, text='log文件名:')
        self.log_fn_label.grid(column=0, row=2)
        self.log_fn = tk.StringVar()
        self.log_fn.set('test.log')
        self.log_fn_entry = ttk.Entry(self.frame, textvariable=self.log_fn)
        self.log_fn_entry.grid(column=1, row=2)
        self.log_fn_btn = ttk.Button(
            self.frame, text='...', command=self._get_log_fn)
        self.log_fn_btn.grid(column=2, row=2)

        self.exec_args_label = ttk.Label(self.frame, text='运行参数:')
        self.exec_args_label.grid(column=0, row=3)
        self.exec_args = tk.StringVar()
        self.exec_args.set('test')
        self.exec_args_entry = ttk.Entry(self.frame, textvariable=self.exec_args)
        self.exec_args_entry.grid(column=1, row=3)

    def _get_exec_fn(self):
        fn = filedialog.askopenfilename(initialdir=".", title="Select exe file", filetypes=(
            ("python file", "*.py"), ("all files", "*.*")))
        self.exec_fn.set(fn)

    def _get_log_fn(self):
        fn = filedialog.asksaveasfilename(initialdir=".", title="Select log file", filetypes=(
            ("log file", "*.log"), ("all files", "*.*")))
        self.log_fn.set(fn)

    def _run(self):
        try:
            self.subp = Popen([sys.executable, self.exec_fn.get(
            ), self.log_fn.get(), self.exec_args.get()], shell=False)
        except Exception as e: 
            msg.showerror('启动失败', f'错误信息：\n{e}')   
            return
        if self.subp.poll() is None: # is running
            self.run_btn['state'] = 'disabled'
            self.stop_btn['state'] = 'normal'
        else:
            msg.showerror('程序没有持续运行', f'返回值：\n{self.subp.returncode}')   
            

    def _close(self):
        pass

    def _stop(self):
        self.subp.kill()
        self.stop_btn['state'] = 'disabled'
        self.run_btn['state'] = 'normal'

class myApp():
    def __init__(self):
        self.win = tk.Tk()
        self.win.title('数采进程管理器v0.3')
        self.win.iconbitmap(r'logo.ico')
        self.win.geometry('500x300')
        self.win.resizable(False, False)
        self.N = 0
        self._ptabs = []
        self.create_widgets()

    def create_widgets(self):
        # menu
        self.menu_bar = Menu(self.win)
        self.win.config(menu=self.menu_bar)

        # file menu
        self.file_menu = Menu(self.menu_bar, tearoff=0)
        self.file_menu.add_command(label='新建进程页',command = self._new_tab)
        self.file_menu.add_command(label='退出当前进程页',command = self._del_tab)
        self.file_menu.add_separator()
        self.file_menu.add_command(label='退出程序', command=self._quit_gui)
        self.menu_bar.add_cascade(label='文件', menu=self.file_menu)

        # help menu
        self.help_menu = Menu(self.menu_bar, tearoff=0)
        self.help_menu.add_command(label='使用说明', command=self._open_help)
        self.help_menu.add_command(label='关于', command=self._msgBox)
        self.menu_bar.add_cascade(label='帮助', menu=self.help_menu)

        # tabs
        self.tab_control = ttk.Notebook(self.win)
        # first tab
        self._new_tab()

    def _new_tab(self):
        """
        新建进程页
        """
        _tab = ttk.Frame(self.tab_control)
        self.tab_control.add(_tab,text=f'数采进程{self.N}')
        self.tab_control.pack(expand=1,fill='both')
        self._ptabs.append( ProcessTab(_tab))
        self.N = self.N + 1

    def _del_tab(self):
        """
        删除进程页
        """
        self.tab_control.forget(self.tab_control.select())

    def _quit_gui(self):
        self.win.quit()
        self.win.destroy()

    def _msgBox(self):
        msg.showinfo(
            '关于', '数采进程管理器\nversion 0.3\n北京嘉时高科科技发展有限公司©2020')

    def _open_help(self):
        Popen('readme.md', shell=True)


# using asycio to replace gui.win.mainloop()
async def updater(win,interval=1/60.0):
    while await asyncio.sleep(interval,True):
        try:
            win.update()
        except tk.TclError as e:
            print(e)
            return 1

def main():
    gui = myApp()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(updater(gui.win))


if __name__ == '__main__':
    sys.exit(main())
